﻿using System;
using System.Collections.Generic;
using System.Threading;
using HtmlParsingLibrary;
using HttpLibrary;
using StockTrader.Core;
using StockTrader.Utilities;
using StockTrader.Utilities.Broker;


namespace StockTrader.Broker.IciciDirect
{
    class PlaceEquityOrderThread_Parameter
    {
        public EquityOrderRecord OrderInformation;
        public ManualResetEvent Completed = new ManualResetEvent(false);
        public BrokerErrorCode ErrorCode;
        internal int Sequence;
    }
    
    public partial class IciciDirectBroker
    {

        // place equity order helper
        ///////////////////////////////////////////////
        //////      PLACE MULTIPLE ORDERS       //////
        /////////////////////////////////////////////                      
        void PlaceEquityOrder_Threaded(object state)
        {
            PlaceEquityOrderThread_Parameter parameter = (PlaceEquityOrderThread_Parameter)state;
            try
            {
                if (EquityOrderType.MARGIN == parameter.OrderInformation.EqOrderType)
                {
                    parameter.ErrorCode = PlaceEquityMarginOrder(parameter.OrderInformation.StockCode,
                        parameter.OrderInformation.Quantity,
                        parameter.OrderInformation.StopLossPrice,
                        parameter.OrderInformation.LimitPrice,
                        parameter.OrderInformation.OrderDirection);
                }
                else
                {
                    parameter.ErrorCode = PlaceEquityDeliveryOrder(parameter.OrderInformation.StockCode,
                        parameter.OrderInformation.Quantity,
                        parameter.OrderInformation.Price,
                        parameter.OrderInformation.OrderPriceType,
                        parameter.OrderInformation.OrderDirection,
                        parameter.OrderInformation.Exchange);

                }
            }
            finally
            {
                parameter.Completed.Set();
            }
        }

        public List<BrokerErrorCode> PlaceMultipleEquityOrders(List<EquityOrderRecord> orders,
    int maxRetries)
        {
            if (orders == null || orders.Count == 0) return new List<BrokerErrorCode>();
            if (maxRetries < 0) maxRetries = 0;
            int numOrders = orders.Count;

            List<BrokerErrorCode> statusCodes = new List<BrokerErrorCode>(numOrders);
            for (int i = 0; i < numOrders; i++)
            {
                statusCodes.Add(BrokerErrorCode.Http);
            }
            int numOrdersPlaced = 0;
            List<PlaceEquityOrderThread_Parameter> parameters = new List<PlaceEquityOrderThread_Parameter>(orders.Count);
            for (int s = 0; s < orders.Count; s++)
            {
                EquityOrderRecord singleOrder = orders[s];
                PlaceEquityOrderThread_Parameter parameter = new PlaceEquityOrderThread_Parameter();
                parameter.OrderInformation = singleOrder;
                parameter.Sequence = s;
                parameters.Add(parameter);
            }
            int numRetries = -1;
            while ((numOrdersPlaced < numOrders) && (numRetries++ < maxRetries))
            {
                for (int s = 0; s < orders.Count; s++)
                {
                    if (parameters[s].ErrorCode == BrokerErrorCode.Success) continue;
                    parameters[s].Completed.Reset();
                    ThreadPool.QueueUserWorkItem(new WaitCallback(PlaceEquityOrder_Threaded), parameters[s]);
                }
                foreach (PlaceEquityOrderThread_Parameter parameter in parameters)
                {
                    parameter.Completed.WaitOne();
                    if (statusCodes[parameter.Sequence] != BrokerErrorCode.Success)
                    {
                        statusCodes[parameter.Sequence] = parameter.ErrorCode;
                        if (parameter.ErrorCode == BrokerErrorCode.Success) numOrdersPlaced++;
                    }
                }
            }
            return statusCodes;
        }

        // get order info from the "order placed successfully page"
        public void GetOrderConfirmationData(string orderPageResponseData, EquityOrderType eqOrderType)
        {
            //if (eqOrderType == EquityOrderType.DELIVERY)
            //{
            //    string subOrderResponseData = StringParser.GetStringBetween(orderPageResponseData,
            //        0,
            //        "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\" bgcolor=\"#ffffff\">",
            //        "</table>",
            //        new string[] { });
            //    ParsedTable table = (ParsedTable)HtmlTableParser.ParseHtmlIntoTables("<table>" + subOrderResponseData + "</table>", true);
            //    //table.PrintTable(null, Console.Out);
            //    string orderRefString = table[i, 7].ToString();
            //    orderRefString = StringParser.GetStringBetween(orderRefString, 0, ">", "</a>", null);
            //    string OrderRefenceNumber = orderRefString.Trim();


            //    for (int i = 1; i < table.RowCount - 1; i++)
            //    {



            //    }

            //}
        }


        //////////////////////////////////////////
        //////      GET EQUITY QUOTE       //////
        ////////////////////////////////////////                 
        // NOTE: We dont want to use IciciGetWebPageResponse here since it updates the login refresh time
        // whereas getting equity quote doesnt actually refresh contact time with server
        // it doesnt even need us to be logged in
        public BrokerErrorCode GetEquityQuote(string stockCode, out EquitySymbolQuote[] info)
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            info = new EquitySymbolQuote[2];

            string quoteData = null;
            int retryCount = 0;
            do
            {
                quoteData = HttpHelper.GetWebPageResponse(
                    URL_ICICI_EQT_QUOTE + stockCode.ToUpper(),
                     null,
                     null,
                     mCookieContainer);
                retryCount++;
            } while (quoteData == null && retryCount < 5);

            if (string.IsNullOrEmpty(quoteData) || quoteData.IndexOf("entered is not valid") > -1)
            {
                // web problems, slow connection, server down etc.
                return BrokerErrorCode.NullResponse;
            }

            quoteData = quoteData.Substring(quoteData.IndexOf("Best 5 Bids/Offers", 0));

            string subQuoteData = StringParser.GetStringBetween(quoteData,
                0,
                "<table width=\"100%\" class=\"projection\">",
                "</table>",
                new string[] { });
        
            ParsedTable table = (ParsedTable)HtmlTableParser.ParseHtmlIntoTables("<table>" + subQuoteData + "</table>", true);

            DateTime result = DateTime.Now;
            bool bSuccess = false;

            // NSE price info
            info[0] = new EquitySymbolQuote();

            info[0].StockCode = stockCode;
            info[0].Exchange = Exchange.NSE;
            bSuccess = DateTime.TryParse(table[1, 4] + " " + table[2, 4], out result);
            if(bSuccess)
                info[0].QuoteTime = result;

            info[0].LastTradePrice = table[1, 1].ToString().Trim();
            info[0].OpenPrice = table[3, 1].ToString().Trim();
            info[0].HighPrice = table[4, 1].ToString().Trim();
            info[0].LowPrice = table[5, 1].ToString().Trim();
            info[0].PreviousClosePrice = table[6, 1].ToString().Trim();
            info[0].PercentageChange = table[8, 1].ToString().Trim();
            info[0].VolumeTraded = table[10, 1].ToString().Trim();

            info[0].BestBidPrice = table[3, 4].ToString().Trim();
            info[0].BestOfferPrice = table[4, 4].ToString().Trim();
            info[0].BestBidQty = table[5, 4].ToString().Trim();
            info[0].BestOfferQty = table[6, 4].ToString().Trim();
            info[0].Price52WkHigh = table[7, 4].ToString().Trim();
            info[0].Price52WkLow = table[8, 4].ToString().Trim();


            // BSE price info
            info[1] = new EquitySymbolQuote();

            info[1].StockCode = stockCode;
            info[1].Exchange = Exchange.BSE;
            bSuccess = DateTime.TryParse(table[1, 5] + " " + table[2, 5], out result);
            if (bSuccess)
                info[1].QuoteTime = result;

            info[1].LastTradePrice = table[1, 2].ToString();
            info[1].OpenPrice = table[3, 2].ToString();
            info[1].HighPrice = table[4, 2].ToString();
            info[1].LowPrice = table[5, 2].ToString();
            info[1].PreviousClosePrice = table[6, 2].ToString();
            info[1].PercentageChange = table[8, 2].ToString();
            info[1].VolumeTraded = table[10, 2].ToString();

            info[1].BestBidPrice = table[3, 5].ToString();
            info[1].BestOfferPrice = table[4, 5].ToString();
            info[1].BestBidQty = table[5, 5].ToString();
            info[1].BestOfferQty = table[6, 5].ToString();
            info[1].Price52WkHigh = table[7, 5].ToString();
            info[1].Price52WkLow = table[8, 5].ToString();

            return errorCode;
        }

        public BrokerErrorCode GetEquitySpread(string stockCode, out EquitySymbolSpread[] info)
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            info = new EquitySymbolSpread[2];

            string quoteData = null;
            int retryCount = 0;
            do
            {
                quoteData = HttpHelper.GetWebPageResponse(
                    URL_ICICI_EQT_SPREAD + stockCode.ToUpper(),
                     null,
                     null,
                     mCookieContainer);
                retryCount++;
            } while (quoteData == null && retryCount < 5);

            // web problems, slow connection, server down etc.
            if (string.IsNullOrEmpty(quoteData) || quoteData.IndexOf("entered is not valid") > -1)
                return BrokerErrorCode.NullResponse;
            
            ParsedTable table = (ParsedTable)HtmlTableParser.ParseHtmlIntoTables(quoteData, true);

            // NSE price info
            info[0] = new EquitySymbolSpread();
            info[0].Symbol = stockCode;
            info[0].Exchange = Exchange.NSE;
            string tempStr = ParsedTable.GetValue(table, new int[] { 0, 3, 0, 1 });
            DateTime lastTradeTime = DateTime.Parse(tempStr);
            tempStr = ParsedTable.GetValue(table, new int[] { 0, 3, 1, 1 });
            lastTradeTime += TimeSpan.Parse(tempStr);
            info[0].QuoteTime = lastTradeTime;

            info[0].TotalBidQty = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, 7, 1 }));
            info[0].TotalOfferQty = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, 8, 1 }));

            for (int i = 0; i < 5; i++)
            {
                info[0].BestBidQty[i] = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 0 }));
                info[0].BestBidPrice[i] = MarketUtils.GetPrice(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 1 }));

                info[0].BestOfferQty[i] = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 2 }));
                info[0].BestOfferPrice[i] = MarketUtils.GetPrice(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 3 }));
            }

            // BSE price info
            info[1] = new EquitySymbolSpread();
            info[1].Symbol = stockCode;
            info[1].Exchange = Exchange.BSE;
            tempStr = ParsedTable.GetValue(table, new int[] { 0, 3, 0, 3 });
            lastTradeTime = DateTime.Parse(tempStr);
            tempStr = ParsedTable.GetValue(table, new int[] { 0, 3, 1, 3 });
            lastTradeTime += TimeSpan.Parse(tempStr);
            info[1].QuoteTime = lastTradeTime;

            info[1].TotalBidQty = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, 7, 3 }));
            info[1].TotalOfferQty = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, 8, 3 }));

            for (int i = 0; i < 5; i++)
            {
                info[1].BestBidQty[i] = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 4 }));
                info[1].BestBidPrice[i] = MarketUtils.GetPrice(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 5 }));

                info[1].BestOfferQty[i] = MarketUtils.GetVolume(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 6 }));
                info[1].BestOfferPrice[i] = MarketUtils.GetPrice(ParsedTable.GetValue(table, new int[] { 0, 5, i + 2, 7 }));
            }
            return errorCode;
        }

        //////////////////////////////////////
        //////      CANCEL ORDER       //////
        ////////////////////////////////////                      

        // IBroker.CancelEquityOrder
        public BrokerErrorCode CancelEquityOrder(string orderRef)
        {
            return CancelEquityOrder(orderRef, true);
        }

        private BrokerErrorCode CancelEquityOrder(string orderRef, bool refreshOrderBook)
        {
            // Login If needed
            BrokerErrorCode errorCode = CheckAndLogInIfNeeded(false);
            if (errorCode != BrokerErrorCode.Success)
            {
                return errorCode;
            }

            if(refreshOrderBook)
            {
                // Make sure we have the latest order book data
                errorCode = RefreshEquityOrderBookToday();
                if (errorCode != BrokerErrorCode.Success)
                {
                    return errorCode;
                }
            }

            EquityOrderBookRecord orderInfo;
            // Search for order in the Orders dictionary
            lock (lockObjectEquity)
            {
                if (mEquityOrderBook.ContainsKey(orderRef))
                {
                    orderInfo = mEquityOrderBook[orderRef];
                }
                else
                {
                    return BrokerErrorCode.OrderDoesNotExist;
                }
            }
                        
            if (orderInfo.Status != OrderStatus.ORDERED &&
                orderInfo.Status != OrderStatus.PARTEXEC &&
                orderInfo.Status != OrderStatus.REQUESTED)
            {
                if (orderInfo.Status == OrderStatus.QUEUED)
                {
                    errorCode = BrokerErrorCode.OrderQueuedCannotCancel;
                }
                else if (orderInfo.Status == OrderStatus.EXECUTED)
                {
                    errorCode = BrokerErrorCode.OrderExecutedCannotCancel;
                }
                else
                {
                    errorCode = BrokerErrorCode.InValidOrderToCancel;
                }
                return errorCode;
            }
            // Instead of getting it actually from order book
            // We simply assume current day only
            DateTime currentDate = MarketUtils.GetMarketCurrentDate();
            string orderStatus = IciciUtils.OrderStatusString[(int)orderInfo.Status];
            string zipCode = orderRef.Substring(8, 2);

            string postData = "FML_PASS=1" +
                "&FML_STATUS=" + orderStatus +
                "&FML_ORDR_RFRNC=" + orderRef +
                // TODO: C for CASH , currently hardcoded. needs to be handled. 
                // Get it in order book stock info somehow
                "&FML_ORD_PRDCT_TYP=C" +
                "&FML_USR_ZIP_CD=" + zipCode + // N5 
                "&check=" +
                "&FML_TRN_PRDT_TYP=O" +
                "&FML_ORD_ORDR_FLW=" + IciciUtils.OrderDirectionString[(int)orderInfo.Direction] + // order direction S/B
                "&FML_ACCOUNT=" + ACCOUNTNUM +
                "&FML_ORD_XCHNG_CD=" + IciciUtils.ExchangeString[(int)orderInfo.Exchange] + // get exchange
                "&FML_ORD_TRD_DT=" + // TODO: Use month name calculation , currently hardcoded "Nov"
                currentDate.ToString("dd") + "-" + currentDate.ToString("MMM") + "-" + currentDate.ToString("yyyy") +
                "&NicValue=" + "&x=" + "&Button1=Yes";

                //"&FML_TO_DT=" +
                //toDate.ToString("dd") + "%2F" + toDate.ToString("MM") + "%2F" + toDate.ToString("yyyy") +
                //"&STCK_CD=All" +
                //"&FML_XCHNG_CD=A" +
                //"&PRDCT_TYPE=A" +
                //"&FML_ORDR_ST=A" +
                //"&FML_ORDR_ACTION=A&Submit=+View+" +
                //"&FML_FOCUS_FLAG=D" +
                //"&FML_TMP_FRM_DT=" + tmpDateToday +
                //"&FML_TMP_TO_DT=" + tmpDateToday +
                //"&FML_ORD_PRDCT_TYP=A" +
                //"&FML_strfinal=" + tmpDateLater +
                //"&FML_ORDR_RFRNC=" + "&FML_ORDR_FLW=" +
                //"&FML_TMP_STTLMNT_NMBR=" +
                //"&FML_STCK_CD=" +
                ////"&FML_SESSION_ID=" + FML_SESSION_ID +
                //"&FML_ORD_DP_ID=" + "&FML_CLNT_ID=" + "&Update=" + "&ButtonDis=" + "&x=" + "&HideLayer=";

            string orderBookData = IciciGetWebPageResponse(URL_ICICI_EQT_CANCEL_ORDER,
                postData,
                URL_ICICI_EQT_HOME,
                mCookieContainer,
                out errorCode);

            if (errorCode.Equals(BrokerErrorCode.Success))
            {

                string cancelConfirm = "Your order has been cancelled";
                string cancelRequestSentToExchange = "Your request for order cancellation has been sent to the exchange";

                // Either cancel confirm or cancellation request sent to exchange both are succes cases
                // Success
                if (orderBookData.Contains(cancelConfirm) || orderBookData.Contains(cancelRequestSentToExchange))
                {
                    // TODO: revist if any prob
                    // Delete the orderRef from mEquityOrderBook
                    // We ideally want it to remain in equity order book in cancelled state
                    // but right now remove it rather than update
                    // because let the GetEquityOrddrBook update it as per its protocol
                    lock (lockObjectEquity)
                    {
                        mEquityOrderBook.Remove(orderRef);
                    }
                    return BrokerErrorCode.Success;
                }
            }

            return BrokerErrorCode.OrderCancelFailed;
        }

        //// Cancel all outstanding orders in the orderbook
        //public BrokerErrorCode CancelAllOutstandingEquityOrders(out Dictionary<string, BrokerErrorCode> cancelOrderErrCodes)
        //{
        //    BrokerErrorCode errorCode = BrokerErrorCode.Unknown;
                
        //    cancelOrderErrCodes = new Dictionary<string, BrokerErrorCode>();

        //    // Make sure we have the latest order book data
        //    errorCode = RefreshEquityOrderBookToday();

        //    if (errorCode != BrokerErrorCode.Success)
        //    {
        //        return errorCode;
        //    }
        //    // Make a clone of mEquityOrderBook for thread saftey
        //    Dictionary<string, EquityOrderBookRecord> EquityOrderToCancel;
        //    lock (lockObjectEquity)
        //    {
        //        EquityOrderToCancel = IciciUtils.CloneDictEquityOrder(mEquityOrderBook);
        //    }

        //    foreach (KeyValuePair<string, EquityOrderBookRecord> orderPair in EquityOrderToCancel)
        //    {
        //        // Try to cancel only cancellable orders
        //        if (orderPair.Value.Status == OrderStatus.ORDERED ||
        //            orderPair.Value.Status == OrderStatus.PARTEXEC ||
        //            orderPair.Value.Status == OrderStatus.REQUESTED)
        //        {
        //            // Trim it
        //            string orderRef = orderPair.Key.Trim(' ', '\t', '\r', '\n');

        //            BrokerErrorCode tmpErrCode = CancelEquityOrder(orderRef);

        //            if (tmpErrCode != BrokerErrorCode.Success)
        //            {
        //                errorCode = tmpErrCode;
        //            }

        //            cancelOrderErrCodes[orderRef] = tmpErrCode;
        //        }
        //    }

        //    return errorCode;

        //}

        // IBroker.CancelAllOutstandingEquityOrders
        // Stock-specific Cancellation of all outstanding orders
        public BrokerErrorCode CancelAllOutstandingEquityOrders(
            string stockCode, 
            out Dictionary<string, BrokerErrorCode> cancelOrderErrCodes)
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;

            cancelOrderErrCodes = new Dictionary<string, BrokerErrorCode>();
            Dictionary<string, EquityOrderBookRecord> stockOrdersToCancel;

            // Make sure we have the latest order book data filtered by stockcode
            errorCode = BrokerUtils.GetEquityOrderBookToday(this, false, true, stockCode, out stockOrdersToCancel);
            if (errorCode != BrokerErrorCode.Success)
            {
                return errorCode;
            }
           
            foreach (KeyValuePair<string, EquityOrderBookRecord> orderPair in stockOrdersToCancel)
            {
                // Try to cancel only cancellable orders
                if (orderPair.Value.Status == OrderStatus.ORDERED ||
                    orderPair.Value.Status == OrderStatus.PARTEXEC ||
                    orderPair.Value.Status == OrderStatus.REQUESTED)
                {
                    // Trim it
                    string orderRef = orderPair.Key.Trim(' ', '\t', '\r', '\n');

                    BrokerErrorCode tmpErrCode = CancelEquityOrder(orderRef, false);

                    if (tmpErrCode != BrokerErrorCode.Success)
                    {
                        errorCode = tmpErrCode;
                    }

                    cancelOrderErrCodes[orderRef] = tmpErrCode;
                }
            }

            return errorCode;

        }

        ////////////////////////////////////
        //////      TRADE BOOK       //////
        //////////////////////////////////                      

        // Filtered trade book for earliest valid day (usually used in "today" context)

        //// Get trade book for a date range filtered by stock code
        //public BrokerErrorCode GetStockFilteredEquityTradeBook(
        //    IBroker broker,
        //    DateTime fromDate,
        //    DateTime toDate,
        //    bool newTradesOnly,
        //    string stockCode,
        //    out Dictionary<string, EquityTradeBookRecord> trades)
        //{
        //    //trades = new Dictionary<string, EquityTradeBookRecord>();
        //    BrokerErrorCode errorCode = broker.GetEquityTradeBook(fromDate, toDate, newTradesOnly, stockCode, trades);
        //    if (errorCode == BrokerErrorCode.Success)
        //    {
        //        trades = FilterTradeBookByStockCode(stockCode);
        //    }

        //    return errorCode;
        //}

        //// Filter the trade book by stock code
        //public Dictionary<string, EquityTradeBookRecord> FilterTradeBookByStockCode(string stockCode)
        //{
        //    Dictionary<string, EquityTradeBookRecord> stockTrades = new Dictionary<string, EquityTradeBookRecord>();
        //    foreach (KeyValuePair<string, EquityTradeBookRecord> tradePair in mEquityTradeBook)
        //    {
        //        if (tradePair.Value.StockCode.Equals(stockCode, StringComparison.OrdinalIgnoreCase))
        //        {
        //            stockTrades.Add(tradePair.Key, tradePair.Value);
        //        }
        //    }
        //    return stockTrades;
        //}

        // For private use


        // IBroker.GetEquityTradeBook

        // Get trade book for a date range and for specific stock if stockCode is valid 
        // else gets complete trade book fro the date range
        public BrokerErrorCode GetEquityTradeBook(DateTime fromDate,
            DateTime toDate,
            bool newTradesOnly,
            string stockCode,
            out Dictionary<string, EquityTradeBookRecord> trades)
        {
            trades = null;
            // Login If needed
            BrokerErrorCode errorCode = CheckAndLogInIfNeeded(false);
            if (errorCode != BrokerErrorCode.Success)
            {
                return errorCode;
            }

            // Session ID not needed as per testing
            //string equityTradingPageData = IciciGetWebPageResponse(URL_ICICI_EQT_TRADEBOOK,
            //    null,
            //    URL_ICICI_EQT_HOME,
            //    mCookieContainer,
            //    out errorCode);

            //if (!errorCode.Equals(BrokerErrorCode.Success))
            //{
            //    return errorCode;
            //}

            //FML_SESSION_ID = StringParser.GetStringBetween(equityTradingPageData,
            //    0,
            //    "<input type=\"hidden\" name=\"FML_SESSION_ID\" value=\"",
            //    "\">",
            //    null);
           							
            DateTime dateToday = DateTime.Today;
            DateTime dateMonthForward = dateToday.AddMonths(1);
            string tmpDateToday = dateToday.ToString("dd") + "%2F" + dateToday.ToString("MM") + "%2F" + dateToday.ToString("yyyy");
            string tmpDateLater = dateMonthForward.ToString("dd") + "%2F" + dateMonthForward.ToString("MM") + "%2F" + dateMonthForward.ToString("yyyy");

            string postData = "FML_PASS=1" +
                "&FML_TRN_PRDT_TYP=O" +
                "&FML_ACCOUNT=" + ACCOUNTNUM +
                "&FML_STCK_CD=" +
                "&FML_FRM_DT=" +
                fromDate.ToString("dd") + "%2F" + fromDate.ToString("MM") + "%2F" + fromDate.ToString("yyyy") +
                "&FML_TO_DT=" +
                toDate.ToString("dd") + "%2F" + toDate.ToString("MM") + "%2F" + toDate.ToString("yyyy") +
                "&FML_XCHNG_CD=ALL" +
                "&FML_ORD_PRDCT_TYP=A" +
                "&FML_ORDR_ACTION=A&Submit=+View+" +
                "&FML_FOCUS_FLAG=D" +
                "&FML_TMP_FRM_DT=" + tmpDateToday +
                "&FML_TMP_TO_DT=" + tmpDateToday +
                "&FML_TMP_STTLMNT_NMBR=" +
                "&FML_strfinal=" + tmpDateLater +
                "&FML_SESSION_ID=" + //FML_SESSION_ID +
                "&FML_ORD_DP_ID=" + "&FML_CLNT_ID=" + "&Update=" + "&ButtonDis=" + "&x=" + "&HideLayer=";

            string tradeBookData = IciciGetWebPageResponse(URL_ICICI_EQT_TRADEBOOK,
                postData,
                URL_ICICI_EQT_HOME,
                mCookieContainer,
                out errorCode);

            if (errorCode.Equals(BrokerErrorCode.Success) && !tradeBookData.Contains("No matching Trades"))
            {
                // Trim it
                tradeBookData = tradeBookData.Trim(' ', '\t', '\r', '\n');

                tradeBookData = HtmlUtilities.EnsureHtmlParsable(tradeBookData);

                string subTradeBookData = StringParser.GetStringBetween(tradeBookData,
                    0,
                    "<table width=\"100%\" border=\"0\" cellspacing=\"1\" cellpadding=\"3\" class=\"projectionSmall\">",
                    "</table>",
                    new string[] { });

                ParsedTable table = (ParsedTable)HtmlTableParser.ParseHtmlIntoTables("<table>" + subTradeBookData + "</table>", true);

                trades = new Dictionary<string, EquityTradeBookRecord>();

                for (int i = 1; i < table.RowCount - 1; i++)
                {
                    EquityTradeBookRecord info = new EquityTradeBookRecord();
                    info.StockCode = table[i, 1].ToString().Trim();
                    // If stockCode parameter is not null i.e. all stocks are intended
                    // and if stock specific orders are intended and current element's stockCode doesnt match then iterate to next element
                    if (!string.IsNullOrEmpty(stockCode) && !info.StockCode.Equals(stockCode, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    DateTime.TryParse(table[i, 0].ToString(), out info.Date);
                    //if (bSuccess)
                    //{
                    //    info[0].UpdateTime = result;
                    //}
                    string tempStr = table[i, 2].ToString().ToUpperInvariant();
                    info.Direction = (OrderDirection)Enum.Parse(typeof(OrderDirection), tempStr);
                    info.Quantity = int.Parse(table[i, 3].ToString());
                    info.Price = double.Parse(table[i, 4].ToString());
                    info.TradeValue = double.Parse(table[i, 5].ToString());
                    tempStr = StringParser.GetStringBetween(table[i, 6].ToString(), 0, "\">", "</a>", null);
                    info.Brokerage = double.Parse(tempStr);
                    string orderRefString = table[i, 7].ToString();
                    orderRefString = StringParser.GetStringBetween(orderRefString, 0, ">", "</a>", null);
                    info.OrderRefenceNumber = orderRefString.Trim();
                    lock (lockObjectEquity)
                    {
                        if (mEquityTradeBook.ContainsKey(info.OrderRefenceNumber))
                        {
                            if (newTradesOnly)
                            { }
                            else
                            {
                                trades.Add(info.OrderRefenceNumber, info);
                            }
                            // Update the trade
                            // update required because PartExec may have become full exec
                            mEquityTradeBook[info.OrderRefenceNumber] = info;
                        }
                        else
                        {
                            mEquityTradeBook.Add(info.OrderRefenceNumber, info);
                            trades.Add(info.OrderRefenceNumber, info);
                        }
                    }
                }
            }
            return errorCode;
        }

        private BrokerErrorCode RefreshEquityTradeBook(
            IBroker broker,
            DateTime fromDate,
            DateTime toDate,
            bool newTradesOnly)
        {
            Dictionary<string, EquityTradeBookRecord> trades;
            return broker.GetEquityTradeBook(DateTime.Today, DateTime.Today, newTradesOnly, null, out trades);
        }

        ////////////////////////////////////
        //////      ORDER BOOK       //////
        //////////////////////////////////    
        // Contains options of getting OrderBook complete, filtered by stock, outstanding orders only
        // fromDate & toDate
     
        //// Get order book for a date range filtered by stock code
        //public BrokerErrorCode GetStockFilteredEquityOrderBook(
        //    IBroker broker, 
        //    DateTime fromDate,
        //    DateTime toDate,
        //    bool newTradesOnly,
        //    bool bOnlyOutstandingOrders,
        //    string stockCode,
        //    out Dictionary<string, EquityOrderBookRecord> orders)
        //{
        //    orders = new Dictionary<string, EquityOrderBookRecord>();
        //    BrokerErrorCode errorCode = broker.GetEquityOrderBook(fromDate, toDate, newTradesOnly);
        //    if (errorCode == BrokerErrorCode.Success)
        //    {
        //        orders = FilterOrderBookByStockCode(stockCode, bOnlyOutstandingOrders);
        //    }

        //    return errorCode;
        //}

        //// Filter the order book by stock code
        //public Dictionary<string, EquityOrderBookRecord> FilterOrderBookByStockCode(string stockCode, bool bOnlyOutstandingOrders)
        //{
        //    Dictionary<string, EquityOrderBookRecord> stockOrders = new Dictionary<string, EquityOrderBookRecord>();
        //    Dictionary<string, EquityOrderBookRecord> equityOrderBook;
        //    lock (lockObjectEquity)
        //    {
        //        equityOrderBook = IciciUtils.CloneDictEquityOrder(mEquityOrderBook);
        //    }
        //    foreach (KeyValuePair<string, EquityOrderBookRecord> orderPair in equityOrderBook)
        //    {
        //        EquityOrderBookRecord orderInfo = orderPair.Value;
        //        if (orderInfo.StockCode.Equals(stockCode, StringComparison.OrdinalIgnoreCase))
        //        {
        //            // Only add valid outstanding orders if bOnlyOutstandingOrders is true
        //            // PARTEXEC is considered OUTSTANDING (i.e. not considered EXEC until fully executed)
        //            if (!bOnlyOutstandingOrders ||
        //                orderInfo.Status == OrderStatus.PARTEXEC ||
        //                orderInfo.Status == OrderStatus.QUEUED ||
        //                orderInfo.Status == OrderStatus.REQUESTED ||
        //                orderInfo.Status == OrderStatus.ORDERED)
        //            {
        //                stockOrders.Add(orderPair.Key, orderInfo);
        //            }
        //        }
        //    }
        //    return stockOrders;
        //}

        // For private use
        private BrokerErrorCode RefreshEquityOrderBookToday()
        {
            DateTime EarliestValidMarketOpenDate = MarketUtils.GetMarketCurrentDate();
            Dictionary<string, EquityOrderBookRecord> orders;
            return GetEquityOrderBook(EarliestValidMarketOpenDate, EarliestValidMarketOpenDate, false, false, null, out orders);
        }

        // IBroker.GetEquityOrderBook
        public BrokerErrorCode GetEquityOrderBook(DateTime fromDate,
            DateTime toDate,
            bool newTradesOnly,
            bool bOnlyOutstandingOrders,
            string stockCode,
            out Dictionary<string, EquityOrderBookRecord> orders)
        {
            orders = null;
            // Login If needed
            BrokerErrorCode errorCode = CheckAndLogInIfNeeded(false);
            if (errorCode != BrokerErrorCode.Success)
                return errorCode;

            DateTime dateToday = DateTime.Today;
            DateTime dateMonthForward = dateToday.AddMonths(1);
            string tmpDateToday = dateToday.ToString("dd") + "%2F" + dateToday.ToString("MM") + "%2F" + dateToday.ToString("yyyy");
            string tmpDateLater = dateMonthForward.ToString("dd") + "%2F" + dateMonthForward.ToString("MM") + "%2F" + dateMonthForward.ToString("yyyy");

            string postData = "FML_PASS=1" +
                "&FML_TRN_PRDT_TYP=O" +
                "&FML_ACCOUNT=" + ACCOUNTNUM +
                "&FML_FRM_DT=" +
                fromDate.ToString("dd") + "%2F" + fromDate.ToString("MM") + "%2F" + fromDate.ToString("yyyy") +
                "&FML_TO_DT=" +
                toDate.ToString("dd") + "%2F" + toDate.ToString("MM") + "%2F" + toDate.ToString("yyyy") +
                "&STCK_CD=All" +
                "&FML_XCHNG_CD=A" +
                "&PRDCT_TYPE=A" +
                "&FML_ORDR_ST=A" +
                "&FML_ORDR_ACTION=A&Submit=+View+" +
                "&FML_FOCUS_FLAG=D" +
                "&FML_TMP_FRM_DT=" + tmpDateToday +
                "&FML_TMP_TO_DT=" + tmpDateToday +
                "&FML_ORD_PRDCT_TYP=A" +
                "&FML_strfinal=" + tmpDateLater +
                "&FML_ORDR_RFRNC=" + "&FML_ORDR_FLW=" +
                "&FML_TMP_STTLMNT_NMBR=" +
                "&FML_STCK_CD=" +
                //"&FML_SESSION_ID=" + FML_SESSION_ID +
                "&FML_ORD_DP_ID=" + "&FML_CLNT_ID=" + "&Update=" + "&ButtonDis=" + "&x=" + "&HideLayer=";

            string orderBookData = IciciGetWebPageResponse(URL_ICICI_EQT_ORDERBOOK,
                postData,
                URL_ICICI_EQT_HOME,
                mCookieContainer,
                out errorCode);

            if (errorCode.Equals(BrokerErrorCode.Success) && !orderBookData.Contains("No matching Orders"))
            {
                // Trim it
                orderBookData = orderBookData.Trim(' ', '\t', '\r', '\n');

                orderBookData = HtmlUtilities.EnsureHtmlParsable(orderBookData);

                string subOrderBookData = StringParser.GetStringBetween(orderBookData,
                    0,
                    "<table width=\"100%\" class=\"projectionSmall\">",
                    "</table>",
                    new string[] { });

                ParsedTable table = (ParsedTable)HtmlTableParser.ParseHtmlIntoTables("<table>" + subOrderBookData + "</table>", true);

                orders = new Dictionary<string, EquityOrderBookRecord>();
                for (int i = 1; i < table.RowCount; i++)
                {
                    EquityOrderBookRecord info = new EquityOrderBookRecord();
                    info.StockCode = table[i, 3].ToString().Trim();

                    // If stockCode parameter is empty/null i.e. all stocks are intended
                    // and if stock specific orders are intended and current element's stockCode doesnt match then iterate to next element
                    if (!string.IsNullOrEmpty(stockCode) && !info.StockCode.Equals(stockCode, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    var temp = table[i, 0].ToString().Split(new string[]{"<br>"}, StringSplitOptions.RemoveEmptyEntries);

                    DateTime.TryParse(temp[0].Trim(), out info.Date);
                    string orderRefString = table[i, 1].ToString();
                    orderRefString = StringParser.GetStringBetween(orderRefString, 0, ">", "</a>", null);
                    // Trim it
                    orderRefString = orderRefString.Trim();//(' ', '\t', '\r', '\n');

                    info.OrderRefenceNumber = orderRefString;
                    string tempStr = table[i, 4].ToString().ToUpperInvariant();
                    info.Direction = (OrderDirection)Enum.Parse(typeof(OrderDirection), tempStr);
                    info.Quantity = int.Parse(table[i, 5].ToString());

                    string price = StringParser.GetStringBetween(table[i, 6].ToString(),
                        0,
                        "<font color=\"blue\">",
                        "</font>",
                        new string[] { });

                    if (String.IsNullOrEmpty(price))
                    {
                        price = StringParser.GetStringBetween(table[i, 6].ToString(),
                        0,
                        "<font color=\"black\">",
                        "</font>",
                        new string[] { });
                    }

                    info.Price = double.Parse(price);

                    tempStr = table[i, 7].ToString().ToUpperInvariant();

                    // Executed orders have different string format, so ignore the clutter
                    if (tempStr.Contains("EXECUTED"))
                    {
                        tempStr = "EXECUTED";
                    }
                    info.Status = (OrderStatus)Enum.Parse(typeof(OrderStatus), tempStr);

                    info.OpenQty = int.Parse(table[i, 9].ToString());
                    info.ExecutedQty = int.Parse(table[i, 10].ToString());
                    info.ExpiredQty = int.Parse(table[i, 11].ToString());
                    info.CancelledQty = int.Parse(table[i, 12].ToString());
                    //info.StopLossPrice = double.Parse(table[i, 15].ToString());

                    // Only add valid outstanding orders if bOnlyOutstandingOrders is true
                    // PARTEXEC is considered OUTSTANDING (i.e. not considered EXEC until fully executed)
                    if (!bOnlyOutstandingOrders ||
                        info.Status == OrderStatus.PARTEXEC ||
                        info.Status == OrderStatus.QUEUED ||
                        info.Status == OrderStatus.REQUESTED ||
                        info.Status == OrderStatus.ORDERED)
                    {
                        lock (lockObjectEquity)
                        {
                            if (mEquityOrderBook.ContainsKey(orderRefString))
                            {
                                if (newTradesOnly)
                                { }
                                else
                                {
                                    orders.Add(orderRefString, info);
                                }
                                // Update the order
                                mEquityOrderBook[orderRefString] = info;
                            }
                            else
                            {
                                mEquityOrderBook.Add(orderRefString, info);
                                orders.Add(orderRefString, info);
                            }
                        }
                    }
                }
            }
            return errorCode;
        }

    }
}
